package com.universal.base.service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.LambdaUtils;
import com.baomidou.mybatisplus.core.toolkit.ReflectionKit;
import com.baomidou.mybatisplus.core.toolkit.support.ColumnCache;
import com.baomidou.mybatisplus.extension.service.IService;
import com.google.common.collect.Lists;
import com.universal.base.entity.CollectionsEntity;
import com.universal.base.entity.PageEntity;
import com.universal.base.entity.RuleEntity;
import com.universal.common.utils.DateUtils;
import org.apache.commons.lang3.StringUtils;

import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * 通用查询
 *
 * @author austin
 * @data 2022/11/14 10:10
 */
public interface IBaseService<T> extends IService<T> {

    /**
     * 获取查询条件
     *
     * @param collectionsEntity
     * @return
     */
    QueryWrapper<T> getQueryWrapper(T collectionsEntity);


    default QueryWrapper<T> getOrderByWrapperCommon(QueryWrapper<T> queryWrapper, List<RuleEntity> ruleEntityList, String orderBy) {

        if (CollectionUtils.isNotEmpty(ruleEntityList)) {
            handlerRuleListWrapper(queryWrapper, ruleEntityList);
        }
        if (StringUtils.isNotBlank(orderBy)) {
            handlerOrderByWrapper(queryWrapper, orderBy);
        }
        return queryWrapper;
    }

    /**
     * 获取排序条件
     *
     * @param queryWrapper
     * @param collectionsEntity
     * @return
     */
    default QueryWrapper<T> getOrderByWrapper(QueryWrapper<T> queryWrapper, CollectionsEntity<T> collectionsEntity) {
        QueryWrapper<T> tQueryWrapper = getOrderByWrapperCommon(queryWrapper, collectionsEntity.getRuleList(), collectionsEntity.getOrderBy());
        return tQueryWrapper;
    }

    /**
     * 获取排序条件
     *
     * @param queryWrapper
     * @param pageEntity
     * @return
     */
    default QueryWrapper<T> getOrderByWrapper(QueryWrapper<T> queryWrapper, PageEntity<T> pageEntity) {
        QueryWrapper<T> tQueryWrapper = getOrderByWrapperCommon(queryWrapper, pageEntity.getRuleList(), pageEntity.getOrderBy());
        return tQueryWrapper;
    }

    /**
     * 获取时间格式的值
     *
     * @param value
     * @return
     */
    default Object getDateValue(Object value) {

        Object val;

        if (value instanceof Number) {
            val = new Date((Long) value);
        } else if (value instanceof String) {
            val = DateUtils.parseDate(value);
        } else {
            val = value;
        }

        return val;
    }


    default void handlerRuleListWrapper(QueryWrapper<T> queryWrapper, List<RuleEntity> list) {
        handlerRuleListWrapper(queryWrapper, list, null);
    }

    /**
     * 获取排序条件
     *
     * @param queryWrapper
     * @param list
     */
    default void handlerRuleListWrapper(QueryWrapper<T> queryWrapper, List<RuleEntity> list, String alias) {

        Class entityClass = ReflectionKit.getSuperClassGenericType(this.getClass(), 1);

        Map<String, Field> fieldMap = ReflectionKit.getFieldMap(entityClass);

        for (RuleEntity ruleEntity : list) {
            String column = getColumn(ruleEntity.getPro(), entityClass);

            if (column == null) {
                continue;  //找不到字段名称，跳过
            }

            if (StringUtils.isNotBlank(alias)) {
                column = alias + "." + column;
            }

            Object value;

            Field field = fieldMap.get(ruleEntity.getPro());

            if (field != null) {

                switch (field.getType().getName()) {
                    case "java.lang.String":
                        value = ruleEntity.getValue();
                        break;
                    case "java.lang.Integer":
                    case "java.lang.Long":
                    case "java.math.BigDecimal":
                    case "java.lang.Float":
                    case "java.lang.Double":
                        if (ruleEntity.getValue() instanceof Collection
                                || ruleEntity.getValue().getClass().isArray()) {
                            value = ruleEntity.getValue();
                        } else {
                            value = BigDecimal.valueOf(Double.valueOf(ruleEntity.getValue().toString()));
                        }
                        break;
                    case "java.util.Date":
                    case "java.time.LocalDate":
                    case "java.time.LocalDateTime":
                    case "java.time.LocalTime":
                        if (ruleEntity.getValue() instanceof Collection) {

                            List<Object> newDateList = Lists.newArrayList();

                            for (Object tmp : (List<Object>) ruleEntity.getValue()) {
                                newDateList.add(this.getDateValue(tmp));
                            }

                            value = newDateList;
                        } else {
                            value = this.getDateValue(ruleEntity.getValue());
                        }

                        break;
                    default:
                        value = ruleEntity.getValue();
                }

            } else {
                value = ruleEntity.getValue();
            }

            switch (ruleEntity.getType()) {
                case RuleEntity.TYPE_EQ:
                    queryWrapper.eq(column, value);
                    break;
                case RuleEntity.TYPE_NE:
                    queryWrapper.ne(column, value);
                    break;
                case RuleEntity.TYPE_LT:
                    queryWrapper.lt(column, value);
                    break;
                case RuleEntity.TYPE_LE:
                    queryWrapper.le(column, value);
                    break;
                case RuleEntity.TYPE_GT:
                    queryWrapper.gt(column, value);
                    break;
                case RuleEntity.TYPE_GE:
                    queryWrapper.ge(column, value);
                    break;
                case RuleEntity.TYPE_LIKE:
                    queryWrapper.like(column, value);
                    break;
                case RuleEntity.TYPE_IN:
                    if (!(value instanceof Collection)) {
                        value = Arrays.asList(value);
                    }
                    queryWrapper.in(column, (Collection) value);
                    break;
                case RuleEntity.TYPE_NOT_IN:
                    if (!(value instanceof Collection)) {
                        value = Arrays.asList(value);
                    }
                    queryWrapper.notIn(column, (Collection) value);
                    break;
                case RuleEntity.TYPE_ISNULL:
                    queryWrapper.isNull(column);
                    break;
                case RuleEntity.TYPE_ISNOTNULL:
                    queryWrapper.isNotNull(column);
                    break;
                default:
                    break;
            }
        }
    }

    /**
     * @param name
     * @param clazz
     * @return
     */
    default String getColumn(String name, Class clazz) {
        name = name.toUpperCase();
        Map<String, ColumnCache> map = LambdaUtils.getColumnMap(clazz);
        if (map.containsKey(name)) {
            return map.get(name).getColumn();
        }
        return name;
    }

    /**
     * 获取排序条件
     *
     * @param queryWrapper
     * @param orderByString
     */
    default void handlerOrderByWrapper(QueryWrapper<T> queryWrapper, String orderByString) {

        Class entityClass = ReflectionKit.getSuperClassGenericType(this.getClass(), 1);

        //默认是句号分隔
        String[] sorts = orderByString.split(",");
        for (String sort : sorts) {
            String type, name;
            if (sort.startsWith("+")) {
                type = "asc";
                name = sort.substring(1);
            } else if (sort.startsWith("-")) {
                type = "desc";
                name = sort.substring(1);
            } else {
                type = "asc";
                name = sort;
            }
            String column = getColumn(name, entityClass);
            if (column != null) {


                if (StringUtils.equals("desc", type)) {
                    queryWrapper.orderByDesc(column);
                } else {
                    queryWrapper.orderByAsc(column);
                }
            } else {
                if (StringUtils.equals("desc", type)) {
                    queryWrapper.orderByDesc(name);
                } else {
                    queryWrapper.orderByAsc(name);
                }
            }
        }
    }

    /**
     * count统计查询默认实现
     *
     * @param entity
     * @return
     */
    default long count(T entity) {
        QueryWrapper<T> getQueryWrapper = checkCondition(entity);
        if (getQueryWrapper == null) {
            return 0;
        }
        return this.count(getQueryWrapper);
    }

    /**
     * list查询的实现
     *
     * @param collectionsEntity
     * @return
     */
    default List<T> list(CollectionsEntity<T> collectionsEntity) {
        QueryWrapper<T> getQueryWrapper = checkCondition(collectionsEntity.getEntity());
        if (getQueryWrapper == null) {
            return null;
        }
        return this.list(getOrderByWrapper(getQueryWrapper, collectionsEntity));
    }

    /**
     * page 查询的实现
     *
     * @param pageEntity
     * @return
     */
    default IPage<T> page(PageEntity<T> pageEntity) {
        QueryWrapper<T> getQueryWrapper = checkCondition(pageEntity.getEntity());
        if (getQueryWrapper == null) {
            return null;
        }
        return this.page(pageEntity, getOrderByWrapper(getQueryWrapper, pageEntity));
    }

    /**
     * getOne 获取单个信息
     *
     * @param entity
     * @return
     */
    default T getOne(T entity) {
        return (T) this.getOne(checkCondition(entity));
    }

    /**
     * 条件检查
     *
     * @param entity
     * @return
     */
    default QueryWrapper checkCondition(T entity) {
        if (entity == null) {
            return null;
        }
        QueryWrapper<T> queryWrapper = getQueryWrapper(entity);
        return queryWrapper;
    }
}
